"""
数据加密服务
实现端到端数据加密和敏感数据保护
"""

import base64
import hashlib
import os
from typing import Optional, Union, Dict, Any
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from sqlalchemy import event
from sqlalchemy.orm import Session
from src.models.user import User
from src.models.user_preference import UserPreference, UserProfile
from src.config.settings import Settings
from src.utils.logging import get_logger

logger = get_logger(__name__)


class DataEncryptionService:
    """数据加密服务类"""
    
    def __init__(self):
        """初始化加密服务"""
        try:
            settings = Settings()
            if hasattr(settings, 'ENCRYPTION_SECRET_KEY') and settings.ENCRYPTION_SECRET_KEY:
                self._key = self._derive_key(settings.ENCRYPTION_SECRET_KEY.encode(), b"salt_")
                self._cipher = Fernet(self._key)
                self._enabled = True
            else:
                logger.warning("未配置加密密钥，数据加密功能将被禁用")
                self._enabled = False
        except Exception as e:
            logger.error(f"初始化加密服务失败: {e}")
            self._enabled = False
    
    def _derive_key(self, password: bytes, salt: bytes) -> bytes:
        """从密码派生加密密钥"""
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(password))
        return key
    
    def encrypt_data(self, data: Union[str, bytes]) -> str:
        """加密数据"""
        if not self._enabled:
            # 如果加密服务未启用，直接返回原始数据
            if isinstance(data, str):
                return data
            elif isinstance(data, bytes):
                return data.decode('utf-8')
            elif isinstance(data, memoryview):  # 处理memoryview类型
                return data.tobytes().decode('utf-8')
            elif isinstance(data, bytearray):  # 处理bytearray类型
                return data.decode('utf-8')
            elif hasattr(data, 'tobytes'):  # 处理其他有tobytes方法的类型
                return data.tobytes().decode('utf-8')
            elif hasattr(data, 'decode'):  # 处理其他有decode方法的类型
                return data.decode('utf-8')
            else:
                return str(data)
            
        if isinstance(data, str):
            data = data.encode()
        encrypted_data = self._cipher.encrypt(data)
        return base64.urlsafe_b64encode(encrypted_data).decode()
    
    def decrypt_data(self, encrypted_data: str) -> str:
        """解密数据"""
        if not self._enabled:
            # 如果加密服务未启用，直接返回原始数据
            return encrypted_data
            
        encrypted_bytes = base64.urlsafe_b64decode(encrypted_data.encode())
        decrypted_data = self._cipher.decrypt(encrypted_bytes)
        return decrypted_data.decode()
    
    def is_enabled(self) -> bool:
        """检查加密服务是否启用"""
        return self._enabled


# 敏感数据识别和保护服务
class SensitiveDataProtectionService:
    """敏感数据识别和保护服务"""
    
    def __init__(self):
        """初始化敏感数据保护服务"""
        # 定义敏感数据模式
        self.sensitive_patterns = {
            'phone': r'1[3-9]\d{9}',
            'email': r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
            'id_card': r'\d{17}[\dXx]|\d{15}',
            'bank_card': r'\d{16}|\d{19}',
            'password': r'["\']?(password|pwd)["\']?s*[:=]s*["\'][^"\']*["\']'
        }
    
    def identify_sensitive_data(self, text: str) -> Dict[str, list]:
        """识别文本中的敏感数据"""
        import re
        
        sensitive_data = {}
        for data_type, pattern in self.sensitive_patterns.items():
            matches = re.findall(pattern, text, re.IGNORECASE)
            if matches:
                sensitive_data[data_type] = matches
        
        return sensitive_data
    
    def mask_sensitive_data(self, text: str, mask_char: str = '*') -> str:
        """对敏感数据进行脱敏处理"""
        import re
        
        # 脱敏电话号码
        text = re.sub(
            r'(1[3-9]\d)(\d{4})(\d{4})',
            rf'\1{mask_char*4}\3',
            text
        )
        
        # 脱敏邮箱
        text = re.sub(
            r'([a-zA-Z0-9._%+-]{2})[a-zA-Z0-9._%+-]*(@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})',
            rf'\1{mask_char*3}\2',
            text
        )
        
        # 脱敏身份证号
        text = re.sub(
            r'(\d{4})\d{10}(\d{4})',
            rf'\1{mask_char*10}\2',
            text
        )
        
        return text


# 数据访问控制服务
class DataAccessControlService:
    """数据访问控制服务"""
    
    def __init__(self):
        """初始化数据访问控制服务"""
        pass
    
    def check_data_access_permission(self, user_role: str, data_type: str) -> bool:
        """检查用户对特定数据类型的访问权限"""
        # 定义角色权限矩阵
        permissions = {
            'admin': {  # 管理员可以访问所有数据
                'user_data': True,
                'user_profile': True,
                'knowledge_graph': True,
                'ticket_data': True,
                'system_config': True
            },
            'agent': {  # 客服可以访问用户数据和工单数据
                'user_data': True,
                'user_profile': True,
                'knowledge_graph': False,
                'ticket_data': True,
                'system_config': False
            },
            'user': {  # 普通用户只能访问自己的数据
                'user_data': True,  # 仅自己的数据
                'user_profile': True,  # 仅自己的数据
                'knowledge_graph': False,
                'ticket_data': True,  # 仅自己的工单
                'system_config': False
            }
        }
        
        role_permissions = permissions.get(user_role, {})
        return role_permissions.get(data_type, False)
    
    def filter_sensitive_fields(self, data: Dict[str, Any], user_role: str) -> Dict[str, Any]:
        """根据用户角色过滤敏感字段"""
        filtered_data = data.copy()
        
        # 定义各角色可访问的敏感字段
        accessible_fields = {
            'admin': set(),  # 管理员可以访问所有字段，无需过滤
            'agent': {'password_hash', 'password_history', 'user_metadata'},
            'user': {'password_hash', 'password_history', 'user_metadata'}
        }
        
        fields_to_remove = accessible_fields.get(user_role, set())
        
        # 移除敏感字段
        for field in fields_to_remove:
            filtered_data.pop(field, None)
        
        return filtered_data


# 全局服务实例
try:
    encryption_service = DataEncryptionService()
except Exception as e:
    logger.error(f"创建加密服务实例失败: {e}")
    encryption_service = None

sensitive_data_service = SensitiveDataProtectionService()
access_control_service = DataAccessControlService()